﻿using CKS.PLC.Core.Event;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

using ZR.Model.Models.ProductionControl;

namespace CKS.PLC.Core
{
    /// <summary>
    /// 设为静态类 
    /// 主要功能是提取方法和热重载
    /// </summary>
    public static class PlcActionDLLManage
    {
        private static readonly object _lockDll = new object();
        private static Type ActionBaseType = null;
        public static string _lastFileHash;
        static string DllName = "CKS.PLC.Action.dll";
        static Assembly assembly = null;
        static FileSystemWatcher watcher = null;
        public static string DllFullPath = "";
        public static void RegisterPlcActionDLL()
        {
            DllFullPath = Path.Combine(Directory.GetCurrentDirectory(), DllName);
            WatchAndReload(DllName);
        }

        private static void WatchAndReload(string dllPath)
        {


            var dllFullPath = Path.Combine(Directory.GetCurrentDirectory(), dllPath);

            ReloadAssembly(dllFullPath);

            watcher = new FileSystemWatcher();
            watcher.Path = Path.GetDirectoryName(dllFullPath);
            watcher.Filter = Path.GetFileName(dllFullPath);
            watcher.NotifyFilter = NotifyFilters.LastWrite;
            watcher.Changed += (sender, e) =>
            {
                // 延迟一段时间以确保文件写入完成
                Thread.Sleep(1000);
                ReloadAssembly(dllPath);
            };
            watcher.Created += (sender, e) =>
            {
                ReloadAssembly(dllPath);
            };

            watcher.EnableRaisingEvents = true;
        }


      

        private static void ReloadAssembly(string dllPath)
        {
            lock (_lockDll)
            {
                // 加载程序集
                // assembly = _currentLoadContext.LoadFromAssemblyPath(dllPath);
                SetTypeInstance(dllPath);

            }
        }

        private static void SetTypeInstance(string dllPath)
        {
            try
            {
                byte[] assemblyBytes = File.ReadAllBytes(dllPath);
                string currentHash = CalculateFileHash(assemblyBytes);
                if (currentHash == _lastFileHash)
                {
                    // 文件内容未变化，忽略事件
                    return;
                }
                _lastFileHash = currentHash;
                EventBus.AddLog($"加载了CKS.PLC.Action.dll");

                // using var stream = new MemoryStream(assemblyBytes);

                assembly = Assembly.Load(assemblyBytes);//AssemblyLoadContext.Default.LoadFromStream(stream);
                string typeName = "CKS.PLC.Action.PLCAction";
                ActionBaseType = assembly.GetType(typeName);
            }
            catch (Exception ex)
            {
                EventBus.AddError(ex,$"加载CKS.PLC.Action.dll出错");
            }
        }

        public static Type GetActionBaseType()
        {
            lock (_lockDll)
            {
                DllFullPath = Path.Combine(Directory.GetCurrentDirectory(), DllName);
                if (ActionBaseType == null)
                    SetTypeInstance(DllFullPath);
                return ActionBaseType;
            }
        }


        private static string CalculateFileHash(byte[] bytes)
        {
            using (var sha256 = SHA256.Create())
            {
                byte[] hashBytes = sha256.ComputeHash(bytes);
                return BitConverter.ToString(hashBytes).Replace("-", "").ToLowerInvariant();
            }
        }
    }
}
